﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows;
using System.Windows.Data;
using System.IO;
using IronPython.Runtime;

namespace LunarSF.SHomeWorkshop.LunarMarkdownEditor.Utils.NPOIHelp
{
    public class 后台任务 : BackgroundWorker
    {
        /// <summary>
        /// 创建后台任务（内部封装了 .net 的 BackgroundWorkder。
        /// </summary>
        /// <param name="taskName">任务名称。</param>
        public 后台任务(string taskName = "新后台任务")
        {
            this.WorkerReportsProgress = true;       // 默认报告进度
            this.WorkerSupportsCancellation = true;  // 默认支持取消

            _任务名称 = taskName;
            taskPanel = new TaskPanel(this);

            DoWork += 后台任务_DoWork;
            ProgressChanged += 后台任务_ProgressChanged;
            RunWorkerCompleted += 后台任务_RunWorkerCompleted;
        }

        public PythonList 暂存进度信息列表 { get; } = new PythonList();


        private void 后台任务_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null){
                sbErr.Append(e.Error.Message + e.Error.StackTrace);
            };

            OnWorkComplete(this, new 任务完成事件参数(e));
            _是否已完成任务 = true;

            if (taskPanel != null)
            {
                taskPanel.pbTaskProcess.Value = taskPanel.pbTaskProcess.Maximum;
            }
        }

        private void 后台任务_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            if (taskPanel != null)
            {
                if (e.UserState.ToString() == "{{初始化任务数}}")
                {
                    // UserState 为 null 时，设置进度条最大值（初始任务数）
                    taskPanel.pbTaskProcess.Maximum = e.ProgressPercentage;
                    taskPanel.pbTaskProcess.Value = 0;
                    return; 
                }
                else
                {
                    // 正常进度
                    var progressPercentage = e.ProgressPercentage;
                    if (progressPercentage < 0) progressPercentage = 0;
                    if (progressPercentage > taskPanel.pbTaskProcess.Maximum) progressPercentage = (int)taskPanel.pbTaskProcess.Maximum;

                    taskPanel.pbTaskProcess.Value = progressPercentage;
                }
            }

            OnProgressChanged(this, new 任务进度事件参数(e));
        }

        private void 后台任务_DoWork(object sender, DoWorkEventArgs e)
        {
            OnDoWork(this, new 任务执行事件参数(e));
        }

        private string _任务名称 = "新后台任务";

        public string 任务名称
        {
            get => _任务名称;
            set => _任务名称 = value;
        }

        private TaskPanel taskPanel;

        public TaskPanel TaskPanel
        {
            get { return taskPanel; }
        }

        public bool 是否支持取消任务
        {
            get => WorkerSupportsCancellation; set => WorkerSupportsCancellation = value;
        }

        public bool 是否支持报告任务进度
        {
            get => WorkerReportsProgress; set => WorkerReportsProgress = value;
        }

        public void 报告任务进度(int percentProgress, object userState)
        {
            ReportProgress(percentProgress, userState);
            this.暂存进度信息列表.Add(userState);
        }

        public bool 是否已取消任务
        {
            get => CancellationPending;
        }

        public bool 是否任务正忙
        {
            get => IsBusy;
        }

        private StringBuilder sbLog = new StringBuilder();

        public StringBuilder SbLog { get => sbLog; }

        public StringBuilder sbErr = new StringBuilder();

        public StringBuilder SbErr { get => sbErr; }

        private bool _是否已完成任务 = false;

        public bool 是否已完成任务
        {
            get => _是否已完成任务;
            set => _是否已完成任务 = value;
        }

        public event EventHandler<任务执行事件参数> 任务执行函数;

        protected void OnDoWork(object sender, 任务执行事件参数 e)
        {
            if (任务执行函数 != null)
            {
                try
                {
                    任务执行函数(sender, e);
                }
                catch (Exception ex)
                {
                    sbErr.Append(任务名称 + " 运行时出错：\r\n" + ex.Message + "\r\n" + ex.StackTrace + "\r\n");
                    this.任务执行函数 -= this.任务执行函数;
                    this.DoWork -= 后台任务_DoWork;
                    throw ex;
                }
            }
        }

        public event EventHandler<任务进度事件参数> 任务进度报告函数;

        protected void OnProgressChanged(object sender, 任务进度事件参数 e)
        {
            if (任务进度报告函数 != null)
            {
                try
                {
                    任务进度报告函数(sender, e);
                }
                catch (Exception ex)
                {
                    sbErr.Append(任务名称 + " 报告进度时出错：\r\n" + ex.Message + "\r\n" + ex.StackTrace + "\r\n");
                }
            }
        }

        public event EventHandler<任务完成事件参数> 任务完成函数;

        protected void OnWorkComplete(object sender, 任务完成事件参数 e)
        {
            if (任务完成函数 != null)
            {
                try
                {
                    if (e.参数体.Error != null || sbErr.Length > 0)
                    {
                        var now = DateTime.Now;
                        var fileName = $"{now.Year}-{now.Month}-{now.Day} {now.Hour}-{now.Minute}-{now.Second}_err_log.txt";
                        var dirName = Globals.PathOfWorkspace + "$_Logs~\\";
                        if (Directory.Exists(dirName) == false)
                        {
                            Directory.CreateDirectory(dirName);
                        }
                        var filePath = Path.Combine(dirName, fileName);
                        System.IO.File.WriteAllText(filePath, sbErr.ToString(), Encoding.UTF8);
                        var tipInfo = "[auto]任务运行期间出错，请查看错误日志文件：" + fileName + "。";
                        if(e.参数体.Error != null && string.IsNullOrWhiteSpace(e.参数体.Error.Message) == false)
                        {
                            tipInfo += "\r\n异常消息：" + e.参数体.Error.Message;
                        }
                        LMessageBox.ShowWarning(tipInfo);
                        System.Diagnostics.Process.Start(filePath);
                        return;
                    }

                    任务完成函数(sender, e);
                }
                catch (Exception ex)
                {
                    LMessageBox.ShowWarning("[auto]" + 任务名称 + " 任务完成时出错。异常消息如下：\r\n" + ex.Message + "\r\n" + ex.StackTrace + "\r\n");
                }
            }
        }

        public event EventHandler<任务取消事件参数> 任务取消函数;

        protected void OnWorkCanceled(object sender, 任务取消事件参数 e)
        {
            if (任务取消函数 != null)
            {
                try
                {
                    // 实测这些不会有机会运行！
                    //if (sbErr.Length > 0)
                    //{
                    //    var now = DateTime.Now;
                    //    var fileName = $"{now.Year}-{now.Month}-{now.Day} {now.Hour}-{now.Minute}-{now.Second}_err_log.txt";
                    //    var dirName = Globals.PathOfWorkspace + "$_Logs~\\";
                    //    if (Directory.Exists(dirName) == false)
                    //    {
                    //        Directory.CreateDirectory(dirName);
                    //    }
                    //    var filePath = Path.Combine(dirName, fileName);
                    //    System.IO.File.WriteAllText(filePath, sbErr.ToString(), Encoding.UTF8);
                    //    LMessageBox.ShowWarning("任务运行期间出错，请查看错误日志文件：" + fileName);
                    //    System.Diagnostics.Process.Start(filePath);
                    //    return;
                    //}
                    任务取消函数(sender, e);
                }
                catch (Exception ex)
                {
                    LMessageBox.ShowWarning("[auto]" + 任务名称 + " 任务取消时出错。异常消息如下：\r\n" + ex.Message + "\r\n" + ex.StackTrace + "\r\n");
                }
            }
        }

        /// <summary>
        /// 这个应通过“进度变化”事件来实现。
        /// </summary>
        /// <param name="taskCount"></param>
        public void 置任务数(int taskCount)
        {
            ReportProgress(taskCount, "{{初始化任务数}}");
        }

        public void 重置进度()
        {
            if (taskPanel != null)
            {
                taskPanel.pbTaskProcess.Value = 0;
            }
        }

        public void 置任务进度(double processValuePercent)
        {
            if (processValuePercent < 0) processValuePercent = 0;

            if (taskPanel != null)
            {
                if (processValuePercent > taskPanel.pbTaskProcess.Maximum)
                    processValuePercent = taskPanel.pbTaskProcess.Maximum;

                taskPanel.pbTaskProcess.Value = processValuePercent;
            }
        }

        public void 追加任务输出信息(string taskInfoLine)
        {
            if (string.IsNullOrWhiteSpace(taskInfoLine)) return;

            taskInfoLine = Utils.Text.FormatLineSplitter(taskInfoLine);

            sbLog.Append(taskInfoLine);
            if (taskPanel != null && taskInfoLine != "{{初始化任务数}}")
            {
                taskPanel.tbTaskProcessInfo.Text += taskInfoLine;
            }
        }

        public void 追加任务输出信息(double taskInfoLine)
        {
            var txt = taskInfoLine.ToString();

            txt = Utils.Text.FormatLineSplitter(txt);

            追加任务输出信息(txt);
        }

        public void 追加任务输出信息行(string taskInfoLine)
        {
            if (string.IsNullOrWhiteSpace(taskInfoLine)) return;

            taskInfoLine = Utils.Text.FormatLineSplitter(taskInfoLine);

            sbLog.Append(taskInfoLine + "\r\n");
            if (taskPanel != null)
            {
                taskPanel.tbTaskProcessInfo.Text += taskInfoLine + "\r\n";
            }
        }

        public void 追加任务输出信息行(double taskInfoLine)
        {
            var txt = taskInfoLine.ToString();

            txt = Utils.Text.FormatLineSplitter(txt);

            追加任务输出信息行(txt);
        }

        public void 置任务输出信息(string taskInfo)
        {
            if (string.IsNullOrWhiteSpace(taskInfo)) return;

            taskInfo = Utils.Text.FormatLineSplitter(taskInfo);

            // sbLog.Clear();
            sbLog.Append(taskInfo);

            if (taskPanel != null && taskInfo != "{{初始化任务数}}")
            {
                taskPanel.tbTaskProcessInfo.Text = taskInfo;
            }
        }

        public void 置任务输出信息(double taskInfo)
        {
            var txt = taskInfo.ToString();
            
            txt = Utils.Text.FormatLineSplitter(txt);

            置任务输出信息(txt);
        }

        public void 置任务输出信息行(string taskInfo)
        {
            if (string.IsNullOrWhiteSpace(taskInfo)) return;

            taskInfo = Utils.Text.FormatLineSplitter(taskInfo);

            // sbLog.Clear();
            sbLog.Append(taskInfo);

            if (taskPanel != null && taskInfo != "{{初始化任务数}}")
            {
                taskPanel.tbTaskProcessInfo.Text = taskInfo;
            }
        }

        public void 置任务输出信息行(double taskInfo)
        {
            var txt = taskInfo.ToString();
            
            txt = Utils.Text.FormatLineSplitter(txt);

            置任务输出信息行(txt);
        }

        public void 开始任务(object argument = null)
        {
            暂存进度信息列表.Clear();

            // 在这里添加控制面板（因为可能涉及多任务，并不适合直接使用“输出信息”面板）
            var listPanel = Globals.MainWindow.TaskListPanel;

            if (listPanel.Items.Contains(this) == false)
            {
                listPanel.Items.Add(taskPanel);

                // taskPanel.Width = listPanel.Width;

                var binding = new Binding();
                binding.Source = listPanel;
                binding.Path = new PropertyPath("ActualWidth");
                binding.Converter = new LunarMarkdownEditor.Converter.MaxWidthOfListBoxItem();
                BindingOperations.SetBinding(taskPanel, TaskPanel.MaxWidthProperty, binding);
            }

            var rdFindAndReplace = Globals.MainWindow.rdFindAndReplace;
            if (rdFindAndReplace.ActualHeight <= 40)
            {
                rdFindAndReplace.Height = new GridLength(140, GridUnitType.Auto);
            }
            Globals.MainWindow.tcFindAndReplace.SelectedItem = Globals.MainWindow.btiTaskPanels;

            RunWorkerAsync(argument);
        }

        public void 执行任务(object argument = null)
        {
            开始任务(argument);
        }

        /// <summary>
        /// 由面板的“取消任务”按钮调用此方法。
        /// </summary>
        public void 取消任务()
        {
            CancelAsync();
        }
    }

    public class 任务执行事件参数
    {
        public 任务执行事件参数(DoWorkEventArgs e)
        {
            this._参数体 = e;
        }

        private DoWorkEventArgs _参数体;

        public DoWorkEventArgs 参数体 { get => _参数体; }

        public object 参数值
        {
            get
            {
                return _参数体?.Argument;
            }
        }

        public object 结果
        {
            get
            {
                return _参数体?.Result;
            }
            set
            {
                if (_参数体 != null)
                {
                    _参数体.Result = value;
                }
            }
        }

        public bool 是否取消
        {
            get
            {
                if (_参数体 == null) return false;
                return _参数体.Cancel;
            }
            set
            {
                if (_参数体 != null)
                {
                    _参数体.Cancel = value;
                }
            }
        }
    }

    public class 任务进度事件参数
    {
        public 任务进度事件参数(ProgressChangedEventArgs e)
        {
            this._参数体 = e;
        }

        private ProgressChangedEventArgs _参数体;

        public ProgressChangedEventArgs 参数体 { get => _参数体; }

        public object 用户状态
        {
            get => this._参数体.UserState == null ? this._参数体.ProgressPercentage.ToString() : this._参数体.UserState.ToString();
        }

        /// <summary>
        /// “用户状态(UserState)”这个翻译并不好懂，所以另外提供此别名。
        /// </summary>
        public object 状态数据
        {
            get => this._参数体.UserState == null ? this._参数体.ProgressPercentage.ToString() : this._参数体.UserState.ToString();
        }

        public int 进度
        {
            get
            {
                if (_参数体 == null)
                {
                    return 0;
                }

                return _参数体.ProgressPercentage;
            }
        }
    }

    public class 任务完成事件参数
    {
        public 任务完成事件参数(RunWorkerCompletedEventArgs e)
        {
            _参数体 = e;
        }

        private RunWorkerCompletedEventArgs _参数体;

        public RunWorkerCompletedEventArgs 参数体 { get => _参数体; }

        public object 结果
        {
            get
            {
                if (this._参数体 == null) return 0;

                return this._参数体.Result;
            }
        }

        public bool 是否取消
        {
            get
            {
                if (this._参数体 == null) return false;

                return this._参数体.Cancelled;
            }
        }

        public Exception 错误
        {
            get
            {
                if (this._参数体 == null) return new Exception("0");

                return this._参数体.Error;
            }
        }
    }

    public class 任务取消事件参数
    {
        public 任务取消事件参数(ProgressChangedEventArgs e)
        {
            _参数体 = e;
        }

        private ProgressChangedEventArgs _参数体;

        public ProgressChangedEventArgs 参数体 { get => _参数体; }

        public string 用户状态
        {
            get => this._参数体.UserState == null ? this._参数体.ProgressPercentage.ToString() : this._参数体.UserState.ToString();
        }

        /// <summary>
        /// “用户状态(UserState)”这个翻译不太好懂，所以提供此别名。
        /// </summary>
        public string 状态数据
        {
            get => this._参数体.UserState == null ? this._参数体.ProgressPercentage.ToString() : this._参数体.UserState.ToString();
        }

        public int 进度
        {
            get
            {
                if (this._参数体 == null) return 0;

                return this._参数体.ProgressPercentage;
            }
        }
    }
}
